import 'package:base_plugin/base_plugin.dart';
import 'package:flutter/material.dart';

class DropDownMenuController extends ChangeNotifier {
  bool isOpen;

  DropDownMenuController({bool initialIsOpen})
      : isOpen = initialIsOpen ?? false;

  void close() {
    isOpen = false;
    notifyListeners();
  }

  void open() {
    isOpen = true;
    notifyListeners();
  }
}

class DropDownMenu extends StatefulWidget {
  final Widget child; //子view
  final Widget dropDownMenu;
  final DropDownMenuController controller;
  final bool isStackChild;
  final bool isTop;
  final bool isDisabled;

  DropDownMenu(
      {Key key,
      this.dropDownMenu,
      this.isTop = false,
      this.child,
      this.isStackChild = false,
      this.isDisabled = false,
      this.controller})
      : super(key: key); //显示的菜单

  @override
  _DropDownMenuState createState() => _DropDownMenuState();
}

class _DropDownMenuState extends State<DropDownMenu> {
  OverlayEntry _entry;
  RelativeRect _position;
  VoidCallback onListener;
  DropDownMenuController _controller;

  void removeEntry() {
    _entry?.remove();
    _entry = null;
  }

  @override
  void initState() {
    super.initState();
    onListener = () {
      if (_controller.isOpen) {
        addEntry();
      } else {
        removeEntry();
      }
    };
    _controller = widget.controller ?? DropDownMenuController()
      ..addListener(onListener);
  }

  void addEntry() {
    removeEntry();
    try {
      context.findRenderObject();
    } catch (e) {
      _controller.removeListener(onListener);
      return;
    }
    // if (_position == null) {
    final RenderBox button = context.findRenderObject();
//      final Offset target = button.localToGlobal(button.size.center(Offset.zero));

    final RenderBox overlayBox = Overlay.of(context).context.findRenderObject();

    _position = RelativeRect.fromRect(
      Rect.fromPoints(
        button.localToGlobal(Offset.zero, ancestor: overlayBox),
        button.localToGlobal(button.size.bottomRight(Offset.zero),
            ancestor: overlayBox),
      ),
      Offset.zero & overlayBox.size,
    );
    // }
    if (widget.isTop == true) {
      double bottom = MediaQuery.of(context).size.height - _position.top;
      if (widget.isStackChild) {
        bottom = _position.bottom + MediaQuery.of(context).viewInsets.bottom;
      }
      Widget child = Positioned.fill(
          child: Material(
        type: MaterialType.transparency,
        child: Stack(
          children: <Widget>[
            PressedOpacityButton(
              onPressed: () {
                _controller.close();
              },
              child: Opacity(
                opacity: 0.0,
                child: Container(
                  width: MediaQuery.of(context).size.width,
                  height: MediaQuery.of(context).size.height,
                  color: Colors.black,
                ),
              ),
            ),
            Positioned(
                left: _position.left,
                right: _position.right,
                bottom: bottom,
                child: widget.dropDownMenu),
          ],
        ),
      ));

      _entry = OverlayEntry(builder: (BuildContext context) => child);
    } else {
      double top = MediaQuery.of(context).size.height - _position.bottom;
      if (widget.isStackChild) {
        top = _position.top;
      }
      Widget child = Positioned.fill(
          child: Material(
        type: MaterialType.transparency,
        child: Stack(
          children: <Widget>[
            PressedOpacityButton(
              onPressed: () {
                _controller.close();
              },
              child: Opacity(
                opacity: 0.0,
                child: Container(
                  width: MediaQuery.of(context).size.width,
                  height: MediaQuery.of(context).size.height,
                  color: Colors.black,
                ),
              ),
            ),
            Positioned(
                top: top,
                left: _position.left,
                right: _position.right,
                child: widget.dropDownMenu),
          ],
        ),
      ));

      _entry = OverlayEntry(builder: (BuildContext context) => child);
    }
    Overlay.of(context, debugRequiredFor: widget).insert(_entry);
  }

  @override
  void didUpdateWidget(covariant DropDownMenu oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (_controller.isOpen) {
          _controller.close();
          return false;
        } else {
          return true;
        }
      },
      child: PressedOpacityButton(
        onPressed: widget.isDisabled
            ? null
            : () {
                if (_controller.isOpen) {
                  _controller.close();
                } else {
                  _controller.open();
                }
              },
        child: widget.child,
      ),
    );
  }
}
